"""
:synopsis: Creates empty Standard geodatabase.
:authors: Riley Baird (OK), Emma Baker (OK)

Implements a tool for an ArcGIS Python Toolbox.
"""



# lib import
from ...lib.session import config
from ...lib.datachanges import StandardGeodatabaseCreation, StandardFeatureClassCreation
from ...lib.misc import get_field_info_for_fc_creation
import sys
import os
import arcpy
import random
import pandas as pd
from arcgis.features import GeoAccessor, GeoSeriesAccessor
try:
    from typing import ClassVar, Optional, Union, Protocol, TypeVar, Generic, TypeVar, overload, get_args, Literal
except:
    pass


random_start_phrase = random.choice(['Make it so!', 'Hello World!', 'As the prophecy foretold...', 'Greetings earthlings.', 'All are bases are belong to us.', 'The Jig is up!'])

# required_dataset_name = "NG911"
# optional_dataset_name = "OptionalLayers"
# tool_switch: str = "CREATE_GDB"

error_list = ["--SHOULDN'T BE USED--", "--SHOULDN'T BE USED--", "--SHOULDN'T BE USED--"]


class CreateGDBTool:
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "1 - Create Standard GDB"
        self.description = "Creates NG911 Standard Geodatabase."
        self.canRunInBackground = False
        self.category = "1 - Prep"

    def getParameterInfo(self):
        """Define parameter definitions"""

        params = []

        output_folder = arcpy.Parameter(
            displayName="Output Folder Location",
            name="output_folder",
            datatype="DEFolder",
            parameterType="Required",
            direction="Input")
        params += [output_folder]

        gdb_name = arcpy.Parameter(
            displayName="Target Geodatabase Name",
            name="gdb_name",
            datatype="GPString",
            parameterType="Required",
            direction="Input")
        params += [gdb_name]

        spatial_ref = arcpy.Parameter(
            displayName="Spatial Reference",
            name="spatial_ref",
            datatype="GPString",
            parameterType="Required",
            direction="Input")
        factory_code_2d = config.gdb_info.spatial_reference_factory_code_2d
        factory_code_3d = config.gdb_info.spatial_reference_factory_code_3d
        spatial_ref.filter.type = "ValueList"
        spatial_ref.filter.list = [f"{arcpy.SpatialReference(factory_code_2d).name} | (2d)", f"{arcpy.SpatialReference(factory_code_3d).name} | (3d)", "--USER SPECIFIED--"]
        spatial_ref.value =  f"{arcpy.SpatialReference(factory_code_2d).name} | (2d)"
        params += [spatial_ref]

        user_spatial_ref = arcpy.Parameter(
            displayName="Spatial Reference",
            name="user_spatial_ref",
            datatype="GPSpatialReference",
            parameterType="Optional",
            direction="Input")
        # user_spatial_ref.value = arcpy.SpatialReference(factory_code_2d)
        params += [user_spatial_ref]

        std_fc_name_value_list = [[config.feature_classes[fc_config_key].name, None, False] for fc_config_key in config.feature_classes]
        disp_parameter_name = f"Standard Feature Classes"
        fc_table = arcpy.Parameter(
            displayName=disp_parameter_name,
            name="fc_table",
            datatype="GPValueTable",
            parameterType="Optional",
            direction="Input")
        fc_table.columns = [['GPString', 'Standard Name', 'ReadOnly'], ['DEFeatureClass', 'Location'], ['GPBoolean', 'Create Blank Feature Class?']]
        fc_table.values = std_fc_name_value_list
        params += [fc_table]

        # OUTPUT
        output_gdb = arcpy.Parameter(
            displayName="Output Geodatabase",
            name="output_gdb",
            datatype="DEWorkspace",
            parameterType="Derived",
            direction="Output")
        params += [output_gdb]

        return params

    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True

    def updateParameters(self, parameters):
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parameter
        has been changed."""
        sr_selected = parameters[2]
        user_sr_selected = parameters[3]
        fc_table = parameters[4]

        if sr_selected.altered and not sr_selected.hasBeenValidated:
            if sr_selected.value == "--USER SPECIFIED--":
                user_sr_selected.enabled = True
            else:
                user_sr_selected.enabled = False
        else:
            user_sr_selected.enabled = False

        if fc_table.altered and not fc_table.hasBeenValidated:
            # Fix FC Table
            new_value_list = []
            for idx, value_list in enumerate(fc_table.values):
                std_fc_name = value_list[0]
                fc_obj = value_list[1]
                blank_fc = value_list[2]
                try:
                    fc_path = arcpy.Describe(fc_obj).catalogPath
                except:
                    fc_path = None
                if fc_path:
                    blank_fc = False
                else:
                    blank_fc = blank_fc
                new_value_list.append([std_fc_name, fc_path, blank_fc])
            fc_table.values = new_value_list
        return

    def updateMessages(self, parameters):
        """Modify the messages created by internal validation for each tool
        parameter.  This method is called after internal validation."""
        return

    def execute(self, parameters, messages):
        """The source code of the tool."""
        output_folder_path = parameters[0].valueAsText
        gdb_name = parameters[1].valueAsText
        sr_from_filter = parameters[2].valueAsText
        user_sr = parameters[3].value
        fc_table = parameters[4].values
        fc_dict = {}
        for idx, value_list in enumerate(fc_table):  # Loop through once
            std_fc_name = value_list[0]
            fc_obj = value_list[1]
            blank_fc = value_list[2]
            try:
                fc_path = str(arcpy.Describe(fc_obj).catalogPath)
            except:
                fc_path = None
            if not blank_fc or blank_fc in ["False", "false", "None", "none", "", " ", "#"]:
                blank_fc = False
            else:
                blank_fc = True
            if not fc_path and not blank_fc:
                continue
            fc_dict[std_fc_name] = fc_path

        arcpy.AddMessage(f"{random_start_phrase}")
        arcpy.AddMessage(f"\nCreating gdb `{gdb_name}`...")
        gdb_sr: arcpy.SpatialReference
        if "--USER SPECIFIED--" != sr_from_filter:
            gdb_sr = arcpy.SpatialReference(sr_from_filter.split(" | ")[0])
        elif user_sr:
            gdb_sr = user_sr
        else:
            arcpy.AddWarning(f"...No Spatial Reference provided... Using config...")
            gdb_sr = arcpy.SpatialReference(config.gdb_info.spatial_reference_factory_code_2d)
        gdb_tool_executable = StandardGeodatabaseCreation(output_folder_path, gdb_name)
        gdb_tool_executable.create_std_gdb(gdb_sr)
        arcpy.AddMessage(f"...Adding Standard Domains to gdb `{gdb_name}`...")
        gdb_tool_executable.assign_domain_to_gdb()
        if fc_dict:
            arcpy.AddMessage(f"...Creating and Adding Standard Feature Class(es)...")
            for std_fc_name in fc_dict.keys():
                user_fc_path = fc_dict[std_fc_name]
                fc = config.get_feature_class_by_name(std_fc_name)
                std_fc_geom = fc.geometry_type
                implement_user_std_fc = StandardFeatureClassCreation(gdb_tool_executable.gdb_path, std_fc_name)
                bad_fc_results = implement_user_std_fc.create_blank_fc(std_fc_geom)
                if bad_fc_results:
                    arcpy.AddError(f"{bad_fc_results}")
                    continue
                if user_fc_path:
                    bad_fc_results = implement_user_std_fc.user_to_std_field_mapping(user_fc_path, None)
                    if bad_fc_results:
                        arcpy.AddWarning(f"{bad_fc_results}")
                        continue

        parameters[-1].value = gdb_tool_executable.gdb_path

        return


if __name__ == "__main__":
    raise Exception("This module is a dependency of an ArcGIS Python Toolbox and should not be executed directly.")